package com.geek.gkfood.service.redis;

import com.geek.gkfood.framework.redis.locker.RedisLuaLocker;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

/**
 * <h1>抢单 lua 脚本执行器。</h1><br/>
 *
 * <pre>
 *     操作 redis-cli 的样例命令：
 *     redis-cli -c -p 6382
 *     127.0.0.1:6382> keys *
 *     127.0.0.1:6382> type {gkfood:snatch:order:2}data:11
 *     127.0.0.1:6382> hgetall {gkfood:snatch:order:2}data:11
 *     127.0.0.1:6382> hget {gkfood:snatch:order:2}data:11 22
 * </pre>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2023/9/24 06:30
 */
@Slf4j
@Component
public class SnatchOrderDeductionUpdateLuaExecutor extends RedisLuaLocker {

    private static final String PREFIX = "gkfood:snatch:order:";

    /** <h2>默认可以存活多少次，从 1 开始累加，累加到该值就无法继续请求了。</h2> **/
    private static final int DEFAULT_ALIVE_TIMES = 10;
    /** <h2>默认可以存活的时间，从该值随着时间递减，若递减至 0 的话，相当于该数据就是失效的了。</h2> **/
    private static final int DEFAULT_ALIVE_SECONDS = 60 * 60;

    @Override
    public String getResourcePath() {
        return "/lua/snatch_order_and_deduction.lua";
    }

    /**
     * <h2>尝试抢单资源占用。</h2>
     *
     * @throws
     * @param: luaModel
     * @return: boolean
     * @author hmilyylimh
     * @date: 2023/9/24
     */
    public boolean tryLock(LuaModel luaModel) {
        // 只是将这里的 {} 去掉了而已，然后继续执行 lua 脚本
        // 最终的结局就是，只要使用了多个 keys 的话，那么就一定要求计算出来的 hash 值是一样的
        int shardingHash = getShardingHash(luaModel.getUserId());
        String countPrefix = "" + PREFIX + shardingHash + ":count:";
        String dataPrefix = "" + PREFIX + shardingHash + ":data:";
        String stockPrefix = "" + PREFIX + shardingHash + ":stock:";
        String maxstockPrefix = "" + PREFIX + shardingHash + ":maxstock:";

        ArrayList<String> keys = Lists.newArrayList(
                countPrefix + luaModel.getUserId(),
                dataPrefix + luaModel.getUserId(),
                stockPrefix + luaModel.getShopId(),
                maxstockPrefix + luaModel.getShopId()
        );
        ArrayList<String> args = Lists.newArrayList(
                luaModel.getOrderId(),
                Integer.toString(DEFAULT_ALIVE_TIMES),
                Integer.toString(DEFAULT_ALIVE_SECONDS),
                luaModel.getOrderJsonStr());

        return super.tryLock(keys, args);
    }

    @Setter
    @Getter
    public static class LuaModel {
        private String userId;
        private String orderId;
        private String shopId;
        private String orderJsonStr;

        public static LuaModel create(String userId,
                                      String orderId,
                                      String shopId,
                                      String orderJsonStr) {
            LuaModel model = new LuaModel();
            model.setUserId(userId);
            model.setOrderId(orderId);
            model.setShopId(shopId);
            model.setOrderJsonStr(orderJsonStr);

            return model;
        }
    }
}